/*
 *
 *
 *     文档创建：jjl, jjl@hzncc.com
 */

//如我们需要测试的模块名称为Decoder，那么它编译生成的头文件名称为VDecoder.h：
#include <Vpacket.h>
#include <verilated.h>

//需要生成波形文件，则需要包含verilated_vcd_c.h
#include <verilated_vcd_c.h>



int gen_phy_recv();

int main(int argc, char **argv){
	int i;
	int clk;
	int data;
	//参数处理
	Verilated::commandArgs(argc, argv);

	//初始化调试模块
	Verilated::traceEverOn(true);

	//生成波形文件的VerilatedVcdC对象指针
	VerilatedVcdC *tfp = new VerilatedVcdC ;

	//生成调用模块类
	Vpacket *top = new Vpacket;

	top->trace(tfp, 99);
	tfp->open("ecat_slave.vcd");

	//对仿真的输入进行初始化
	top->sys_reset_n 	= 0;
	top->rxd 		= 0;
	top->rxdv 		= 0;
	top->sys_clk 		= 1;

	
	//while (!Verilated::gotFinish()){
	//	top->eval();
	//}

	// 运行1000个clk
	for(i=0; i< 2000; i++){
		top->sys_reset_n  = (i>2);

		//产生数据
		if(	i > 10 )
			data = gen_phy_recv();

		top->rxdv	= (data & 0x04)? 1: 0;
		top->rxd	= data & 0x03;

		for(clk=0; clk<2; clk ++){
			tfp->dump(2*i + clk);
			top->sys_clk = ! top->sys_clk; //位置和初始值很重要
			top->eval(); // 时钟步进一个周期，上升沿，

		}
		


		if(Verilated::gotFinish())
			exit(0);
	}

	tfp->close();
	delete top;
	delete tfp;
	return 0;
}

//测试报文
const unsigned char pkt1[252] = {
0x24, 0x8f, 0xff, 0xff, 0x24, 0xff, 0x00, 0xe0, /* ........ */
0x0c, 0x68, 0x5e, 0x02, 
//协议
0x88, 0xa4, 
//ECAT头
0xe8, 0x10, /* .h^..... */
//子报文头部
0x0b, 0x7b, 0x00, 0x00, 0x00, 0x00, 0x14, 0x80, /* .{...... */
0x00, 0x00, 

0x0f, 0x00, 0x08, 0x00, 0xc0, 0x61, /* .......a */
0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ........ */
0x00, 0x00, 0x00, 0x00, 0x55, 0x55, 0x17, 0x35, /* ........ */ //修改WKC = 0x1735

0x0a, 0x7c, 0x14, 0x00, 0x00, 0x00, 0x24, 0x80, /* .|....$. */
0x00, 0x00, 
0x37, 0x12, 0x08, 0x00, 0xc0, 0x61, /* ..7....a */
0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1a, 0x00, /* ........ */
0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ........ */
0x00, 0x00, 0x08, 0x00, 0x17, 0xaa, 0x08, 0x00, /* ........ */
0x27, 0xaa, 0x01, 0x00, 0x0f, 0x0f, 0x00, 0x00, /* '....... */
0x0b, 0x7d, 0x38, 0x00, 0x00, 0x00, 0x11, 0x80, /* .}8..... */
0x00, 0x00, 0x0f, 0x00, 0x08, 0x9e, 0x17, 0x09, /* ........ */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ........ */
0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x7e, 0x49, /* ......~I */
0x00, 0x00, 0x00, 0x13, 0x80, 0x00, 0x00, 0x37, /* .......7 */
0x52, 0x08, 0x00, 0x00, 0x9e, 0x17, 0x09, 0x00, /* R....... */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ........ */
0x00, 0x00, 0x00, 0x00, 0x0b, 0x7f, 0x5c, 0x00, /* ......\. */
0x00, 0x00, 0x11, 0x80, 0x00, 0x00, 0x0f, 0x00, /* ........ */
0x08, 0x63, 0xde, 0x04, 0x00, 0x00, 0x00, 0x00, /* .c...... */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ........ */
0x00, 0x0a, 0x80, 0x6d, 0x00, 0x00, 0x00, 0x13, /* ...m.... */
0x80, 0x00, 0x00, 0x37, 0x52, 0x08, 0x58, 0x01, /* ...7R.X. */
0x63, 0xde, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, /* c....... */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ........ */

0x0e, 0x81, 
0x01, 0x00, 0x10, 0x09, 
0x04, 0x80, /* ........ */
0x00, 0x00, 
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ........ */
0x04, 0x82, 
0x01, 0x00, 0x90, 0x09, 
0x04, 0x00, /* ........ */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  /* ........ */
//报文无FCS，添加4个字节，随机值
0x23, 0x21, 0x33, 0x99
};

//一次调用产生一个phy_rxdv, phy_rxd
static int call_num = 0;
int gen_phy_recv()
{
	int pos = 0;
	int snd = 0;
	unsigned char temp = 0;
	call_num++;
	//帧定界符，7个AA+1个AB
	if(call_num < 31)
		return 0x04 | 0x01; //bit3:rxdv, bit1-0:rxd：2'01
	if(call_num == 31)
		return 0x04 | 0x03; //rxd = 2'b11
	
	//计算数组元素的位置
	pos = (call_num - 32)>>2;

	//当发送完毕后，空闲一段时间
	if(pos > 280){
		call_num = 0;	//重置发送指针
		return 0; //rxdv=0, rxd=00
	}
	if(pos > 251){
		//call_num = 0;	//重置发送指针
		return 0; //rxdv=0, rxd=00
	}

	temp = pkt1[pos];
	snd = 0x04;	//rxdv=1
	//先发送低位，再发送高位
	switch(call_num & 0x03){
		case 0: snd |= (temp & 0x03);break;
		case 1: snd |= (temp & 0x0c)>>2;break;
		case 2: snd |= (temp & 0x30)>>4;break;
		case 3: snd |= (temp & 0xc0)>>6;break;
	}
	return snd;
}
